import { director, Node, UITransform } from "cc";
import { forceGuideMediator } from "./forceGuideMediator";
import { guideCenter } from "./guideCenter";
import { guideDataCtrl } from "./guideDataCtrl";
import { GuideCmd, GuideExeSequence, IGuideConfig, IGuideMediator, IGuideStep, IRuningGuide } from "./iGuide";
import { weakGuideMediator } from "./weakGuideMediator";

export class guideMgr {
    private static _inst: guideMgr;
    public static get Inst(): guideMgr {
        if (!this._inst) {
            this._inst = new guideMgr();
        }
        return this._inst;
    }

    private _nodeTrans: UITransform;
    private _isNeedGuide: boolean = true;
    private _isNeedDebug: boolean = true;
    private _guideQueue: IRuningGuide[];
    private _runningGuideMap: Map<number, IRuningGuide>;
    private _guideMediatorMap: Map<GuideCmd, IGuideMediator>;
    private _dataCtrl: guideDataCtrl;

    constructor() {
        var node = new Node("Guide");
        director.getScene().addChild(node);
        this._nodeTrans = node.addComponent(UITransform);
        this._guideQueue = [];
        this._runningGuideMap = new Map<number, IRuningGuide>();
        this._guideMediatorMap = new Map<GuideCmd, IGuideMediator>();
        this._dataCtrl = new guideDataCtrl();
        this._dataCtrl.init();

        this.bindMediator(GuideCmd.WeakGuide, new weakGuideMediator(this));
        this.bindMediator(GuideCmd.ForceGuide, new forceGuideMediator(this));
    }

    public update(dt: number): void {
        for (var mediator of this._guideMediatorMap.values()) {
            mediator.update(dt);
        }
    }

    public runGuides() {
        //开始时运行未完成的引导
        for (let i = this._dataCtrl.localGuides.length - 1; i >= 0; i--) {
            var guideId = this._dataCtrl.localGuides[i];
            var cfg = guideCenter.getGuide(guideId);
            this.runGuide(cfg);
        }
    }

    public triggerGuide(guideId: number) {
        //1.检查该引导是否完成过了
        var cfg = guideCenter.getGuide(guideId);
        var stepId = this._dataCtrl.getCompleteStepId(guideId);
        if (stepId >= cfg.steps.length - 1) {
            //说明已经完成了
            if (this._isNeedDebug)
                console.log(`引导:${cfg.name} id:${cfg.id}已经完成啦，不在重复执行`);

            return;
        }
        //2.记录本地运行引导缓存
        if (!!cfg.isLocalSave)
            this._dataCtrl.saveLocalGuide(guideId);

        //3.根据引导缓存执行引导
        this.runGuide(cfg);
    }

    public cancleGuide(guideId: number) {
        //队列删除
        var idx = this._guideQueue.findIndex(v => v.config.id == guideId);
        this._guideQueue.splice(idx, 1);
        this._runningGuideMap.delete(guideId);
        if (this._isNeedDebug)
            console.log(`取消引导，id:${guideId}`);
    }

    public stepOver(guideId: number, stepId: number) {
        if (!this._runningGuideMap.has(guideId))
            return;

        var runGuide = this._runningGuideMap.get(guideId);
        var step = runGuide.steps[0];
        step.onEnd && step.onEnd();
        runGuide.steps.shift();

        runGuide.stepIdx = stepId > 0 ? stepId : runGuide.stepIdx;

        //还没完成这个正式步骤
        if (runGuide.steps.length > 0) {
            //继续小步骤
            this.runStep(guideId, runGuide.steps[0]);
        } else {

            if (this._isNeedDebug)
                console.log(`完成引导:${runGuide.config.name}的step：${step.desc} id:${step.id}`);

            //同步至服务端
            if (!!step.isSaveServer) {
                this._dataCtrl.setCompleteStep(guideId, runGuide.stepIdx);
            }

            //大步骤++
            runGuide.stepIdx++;
            this._runningGuideMap.delete(guideId);
            if (runGuide.stepIdx >= runGuide.config.steps.length) {
                //彻底完成
                this.completeGuide(runGuide.config);

                if (this._isNeedDebug)
                    console.log(`彻底完成引导:${runGuide.config.name}  id:${runGuide.config.id}`);

                this.getMediator(step.command.cmd)?.complete();

                if (runGuide.config.exeSequence == GuideExeSequence.Queue) {
                    //队列删除
                    var idx = this._guideQueue.findIndex(v => v.config.id == guideId);
                    this._guideQueue.splice(idx, 1);
                    this.runQueue();
                }

            } else {
                this.exeGuideStep(runGuide);
            }
        }
    }

    private runGuide(cfg: IGuideConfig) {
        var guideId = cfg.id;
        if (!this._isNeedGuide) {
            this.completeGuide(cfg);
            return;
        }

        if (!cfg.isRunGuide) {
            if (this._isNeedDebug)
                console.log(`跳过引导:${cfg.name}  id:${guideId}`);

            this.completeGuide(cfg);
            return;
        }

        //获取完成步骤情况
        var startStepId = this._dataCtrl.getCompleteStepId(guideId) + 1;
        //已经完成过了呀
        if (startStepId >= cfg.steps.length) {
            this._dataCtrl.localGuideComplete(guideId);
            return;
        }

        var runGuide = <IRuningGuide>{
            config: cfg,
            isInPreStep: startStepId > 0,
            stepIdx: startStepId,
            steps: [],
        }

        if (cfg.exeSequence == GuideExeSequence.Queue) {
            //重复过滤
            if (!this._guideQueue.find(v => v.config.id == cfg.id))
                this._guideQueue.push(runGuide);

            this.runQueue();
        } else {
            //立刻执行
            this.exeGuideStep(runGuide);
        }
    }

    private completeGuide(cfg: IGuideConfig) {
        cfg.onComplete && cfg.onComplete();
        //删除缓存
        this._dataCtrl.localGuideComplete(cfg.id);
    }

    private runQueue() {
        if (this._guideQueue.length == 1) {
            //立刻执行
            this.exeGuideStep(this._guideQueue[0]);
        }
    }

    private exeGuideStep(guide: IRuningGuide) {
        if (this._runningGuideMap.has(guide.config.id))
            return;

        guide.steps = [];
        var step = guide.config.steps[guide.stepIdx];
        step.id = guide.stepIdx;
        //判断当前步骤是否有预处理步骤
        if ((!!guide.isInPreStep || guide.stepIdx == 0) && step.preSteps && step.preSteps.length > 0) {
            step.preSteps.forEach(id => {
                var steps = guide.config.preStepsMap.get(id);
                if (!steps) {
                    console.error(`获取前置步骤失败：${id}`);
                    return;
                }
                steps.forEach(tempStep => {
                    //前置步骤绝对不缓存
                    tempStep.isSaveServer = false;
                    tempStep.id = -1;
                    guide.steps.push(tempStep);
                })
            });
            //后续的就不需要前置条件了
            guide.isInPreStep = false;
        }

        //再把自己加进去
        guide.steps.push(step);
        console.log(`当前引导步骤列表:`, guide.steps);
        this._runningGuideMap.set(guide.config.id, guide);

        this.runStep(guide.config.id, guide.steps[0]);
    }

    private runStep(guideId: number, step: IGuideStep) {
        step.onInit && step.onInit();
        let runFunc = () => {
            step.onStart && step.onStart();
            this.getMediator(step.command.cmd)?.run(guideId, step.id, step.command.args);

            if (this._isNeedDebug)
                console.log(`开始引导:${guideId}的step：${step.desc} id:${step.id}`);
        }

        //延迟？
        if (step.delay && step.delay > 0) {
            this.scheduleOnce(runFunc, step.delay);
        } else {
            runFunc();
        }
    }

    private scheduleOnce(func: Function, time: number) {
        this._nodeTrans.scheduleOnce(func, time);
    }

    private bindMediator(type: GuideCmd, cls: IGuideMediator) {
        this._guideMediatorMap.set(type, cls);
    }

    private getMediator(type: GuideCmd): IGuideMediator {
        if (!this._guideMediatorMap.has(type)) {
            console.error(`未绑定当前类型的GuideMediator：${type}`);
            return;
        }
        return this._guideMediatorMap.get(type);
    }
}


